package com.hup.htts.service.tts;

import com.hup.htts.service.tts.jna.HttsJnaLib;
import com.hup.htts.service.tts.jna.SAPIHResultException;
import com.hup.htts.service.tts.jna.SAPIHResultException.HResult;
import com.hup.htts.service.tts.jna.VoiceInfo;
import com.hup.utils.commons.thread.component.PrefixAbleThreadFactory;
import com.hup.utils.commons.thread.component.SimpleRejectedHandler;
import com.sun.jna.WString;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.concurrent.Callable;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author hugan
 * @date 2021/9/13
 */
@Log4j2
@Component
public class TTSService {
    private static final HttsJnaLib INSTANCE = HttsJnaLib.INSTANCE;

    private final ThreadPoolExecutor executor;
    /**
     * 是否已初始化dll模块
     */
    @Getter
    private boolean inited = false;
    /**
     * 是否打印dll的debug信息,需要在init前调用
     */
    @Setter
    private boolean showDllDebug = false;
    /**
     * 设置回调
     */
    @Setter
    private TTSCallback callback;

    public TTSService() {
        executor = new ThreadPoolExecutor(
                1,
                1,
                0, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(),
                new PrefixAbleThreadFactory("TTSService"),
                new SimpleRejectedHandler("语音合成器"));
    }

    /**
     * 调用模块功能
     */
    private void callDll(String desc, Callable<Integer> task) {
        executor.execute(() -> {
            try {
                if (!inited) {
                    log.warn("模块未初始化:{}", desc);
                    return;
                }
                SAPIHResultException.testThrow(task.call());
            } catch (Throwable e) {
                if (callback != null) callback.onErr(desc, e);
            }
        });
    }

    /**
     * 初始化模块
     */
    public void init() {
        if (inited) return;
        executor.execute(() -> {
            int hr = INSTANCE.init(showDllDebug);
            inited = HResult.succeeded(hr);
            try {
                SAPIHResultException.testThrow(hr);
            } catch (Throwable e) {
                if (callback != null) callback.onErr("初始化语音模块", e);
            }
        });
    }

    /**
     * 释放模块
     */
    public void doTerminate() {
        executor.execute(() -> {
            //即使init错误,也doFree
            INSTANCE.doFree();
            executor.shutdown();
        });
    }

    @Override
    protected void finalize() throws Throwable {
        log.info("finalize");
        doTerminate();
        super.finalize();
    }

    /**
     * 获取语音引擎
     */
    public void getVoices() {
        callDll("获取语音引擎", () -> {
            ArrayList<VoiceInfo> res = new ArrayList<>();
            //int hr = INSTANCE.enumVoice(res::add);
            int hr = INSTANCE.enumVoice(name -> {
                //log.info("name={}", name);
                VoiceInfo voiceInfo = new VoiceInfo();
                voiceInfo.name = name;
                res.add(voiceInfo);
            });
            if (HResult.succeeded(hr) && callback != null) {
                callback.onGetVoices(res);
            }
            return hr;
        });
    }

    /**
     * @param voiceIndex enumVoice中得到的引擎index
     */
    public void setVoice(int voiceIndex) {
        callDll("设置语音引擎", () -> INSTANCE.setVoice(voiceIndex));
    }

    /**
     * @param volume 音量[0,100],默认是100
     */
    public void setVolume(int volume) {
        callDll("设置音量", () -> INSTANCE.setVolume(getSafeVolume(volume)));
    }

    /**
     * @param rate 播放速度[-10,10],默认是0
     */
    public void setRate(int rate) {
        callDll("设置语速", () -> INSTANCE.setRate(getSafeRate(rate)));
    }

    public void speak(String text) {
        callDll("朗读", () -> INSTANCE.speak(new WString(text)));
    }

    public void stop() {
        callDll("停止朗读", INSTANCE::stop);
    }

    public void pause() {
        callDll("暂停朗读", INSTANCE::pause);
    }

    public void resume() {
        callDll("恢复朗读", INSTANCE::resume);
    }

    /**
     * @return 通过校验的volume
     */
    public static int getSafeVolume(int volume) {
        if (volume < 0 || volume > 100) {
            return 100;
        }
        return volume;
    }

    /**
     * @return 通过校验的rate
     */
    public static int getSafeRate(int rate) {
        if (rate < -10 || rate > 10) {
            return 0;
        }
        return rate;
    }

    public interface TTSCallback {

        void onGetVoices(ArrayList<VoiceInfo> voiceInfos);

        void onErr(String desc, Throwable e);

    }

}
